# customer_segmentation.py - 客户分群和用户画像
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.metrics import silhouette_score
import numpy as np
from config import MODEL_CONFIG


class CustomerSegmentation:
    def __init__(self, user_features):
        self.user_features = user_features
        self.scaler = StandardScaler()
        self.kmeans_model = None
        self.cluster_labels = None

    def prepare_features(self):
        """准备聚类特征"""
        # 选择数值特征
        numeric_features = self.user_features.select_dtypes(include=[np.number])

        # 移除可能不适合聚类的特征
        columns_to_exclude = ['最近购买间隔', '客户生命周期', '总消费额', '购买频次']
        features_for_clustering = numeric_features.drop(
            columns=[col for col in columns_to_exclude if col in numeric_features.columns],
            errors='ignore'
        )

        # 处理缺失值
        features_for_clustering = features_for_clustering.fillna(0)

        print(f"用于聚类的特征维度: {features_for_clustering.shape}")
        return features_for_clustering

    def find_optimal_clusters(self, features):
        """使用肘部法则和轮廓系数确定最佳聚类数"""
        wcss = []
        silhouette_scores = []
        range_values = MODEL_CONFIG['n_clusters_range']

        for i in range_values:
            if i == 1:
                silhouette_scores.append(0)  # 单个聚类时轮廓系数为0
                continue

            kmeans = KMeans(n_clusters=i, random_state=MODEL_CONFIG['random_state'], n_init=10)
            cluster_labels = kmeans.fit_predict(features)
            wcss.append(kmeans.inertia_)
            silhouette_scores.append(silhouette_score(features, cluster_labels))

        # 绘制肘部法则和轮廓系数图
        plt.figure(figsize=(15, 5))

        # 肘部法则
        plt.subplot(1, 2, 1)
        plt.plot(range_values, [0] + wcss, marker='o')
        plt.title('肘部法则 - 最佳聚类数')
        plt.xlabel('聚类数')
        plt.ylabel('WCSS')

        # 轮廓系数
        plt.subplot(1, 2, 2)
        plt.plot(range_values, silhouette_scores, marker='o', color='red')
        plt.title('轮廓系数 - 最佳聚类数')
        plt.xlabel('聚类数')
        plt.ylabel('轮廓系数')

        plt.tight_layout()
        plt.show()

        # 选择最佳聚类数（轮廓系数最高）
        optimal_clusters = range_values[np.argmax(silhouette_scores)]
        print(f"推荐聚类数: {optimal_clusters} (轮廓系数: {max(silhouette_scores):.3f})")

        return optimal_clusters

    def perform_clustering(self, n_clusters=4):
        """执行K-means聚类"""
        features = self.prepare_features()

        # 标准化特征
        scaled_features = self.scaler.fit_transform(features)

        # 训练K-means模型
        self.kmeans_model = KMeans(
            n_clusters=n_clusters,
            random_state=MODEL_CONFIG['random_state'],
            n_init=10
        )
        self.cluster_labels = self.kmeans_model.fit_predict(scaled_features)

        # 将聚类结果添加到用户特征中
        self.user_features['客户分群'] = self.cluster_labels

        # 计算轮廓系数
        silhouette_avg = silhouette_score(scaled_features, self.cluster_labels)
        print(f"聚类完成，轮廓系数: {silhouette_avg:.3f}")

        return self.cluster_labels

    def visualize_clusters(self):
        """可视化聚类结果"""
        features = self.prepare_features()
        scaled_features = self.scaler.fit_transform(features)

        # 使用PCA降维可视化
        pca = PCA(n_components=2)
        pca_features = pca.fit_transform(scaled_features)

        plt.figure(figsize=(15, 6))

        # PCA散点图
        plt.subplot(1, 2, 1)
        scatter = plt.scatter(pca_features[:, 0], pca_features[:, 1],
                              c=self.cluster_labels, cmap='viridis', alpha=0.6)
        plt.colorbar(scatter)
        plt.title('客户分群可视化 (PCA降维)')
        plt.xlabel(f'主成分1 ({pca.explained_variance_ratio_[0]:.2%})')
        plt.ylabel(f'主成分2 ({pca.explained_variance_ratio_[1]:.2%})')

        # 特征对比图
        plt.subplot(1, 2, 2)
        cluster_profiles = self.user_features.groupby('客户分群').agg({
            '总消费额': 'mean',
            '购买频次': 'mean',
            '平均消费额': 'mean',
            '客单价': 'mean',
            '优惠券使用率': 'mean'
        }).round(2)

        cluster_profiles.plot(kind='bar', ax=plt.gca())
        plt.title('各客户分群特征对比')
        plt.xticks(rotation=0)
        plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')

        plt.tight_layout()
        plt.show()

    def create_customer_profiles(self):
        """创建客户画像"""
        print("\n=== 客户价值分群画像 ===")

        cluster_descriptions = {}
        key_metrics = ['总消费额', '购买频次', '平均消费额', '客单价', '优惠券使用率']

        for cluster_id in sorted(self.user_features['客户分群'].unique()):
            cluster_data = self.user_features[self.user_features['客户分群'] == cluster_id]

            # 计算关键指标
            avg_spend = cluster_data['总消费额'].mean()
            avg_frequency = cluster_data['购买频次'].mean()
            avg_amount = cluster_data['平均消费额'].mean()
            overall_avg_spend = self.user_features['总消费额'].mean()
            overall_avg_freq = self.user_features['购买频次'].mean()

            # 基于RFM思路分类
            if avg_spend > overall_avg_spend and avg_frequency > overall_avg_freq:
                description = "高价值客户 - 高频高消费优质客户"
                strategy = "VIP维护策略"
            elif avg_spend > overall_avg_spend and avg_frequency <= overall_avg_freq:
                description = "重要发展客户 - 高消费但频次中等"
                strategy = "频次提升策略"
            elif avg_spend <= overall_avg_spend and avg_frequency > overall_avg_freq:
                description = "潜力客户 - 高频次但消费金额中等"
                strategy = "客单价提升策略"
            else:
                description = "一般价值客户 - 低频低消费"
                strategy = "激活策略"

            cluster_descriptions[cluster_id] = {
                'description': description,
                'strategy': strategy,
                'size': len(cluster_data),
                'metrics': cluster_data[key_metrics].mean().to_dict()
            }

            # 输出分群信息
            print(f"\n分群 {cluster_id}: {description}")
            print(f"  客户数量: {len(cluster_data)} ({len(cluster_data) / len(self.user_features):.1%})")
            print(f"  推荐策略: {strategy}")
            print(f"  平均总消费额: ¥{cluster_data['总消费额'].mean():.2f}")
            print(f"  平均购买频次: {cluster_data['购买频次'].mean():.2f}")
            print(f"  平均客单价: ¥{cluster_data['客单价'].mean():.2f}")
            print(f"  平均优惠券使用率: {cluster_data['优惠券使用率'].mean():.2%}")

        # 绘制客户分群分布
        self._plot_cluster_distribution()

        return cluster_descriptions

    def _plot_cluster_distribution(self):
        """绘制客户分群分布图"""
        plt.figure(figsize=(12, 5))

        # 饼图
        plt.subplot(1, 2, 1)
        cluster_dist = self.user_features['客户分群'].value_counts().sort_index()
        colors = ['lightcoral', 'lightblue', 'lightgreen', 'gold', 'lightpink', 'lightskyblue']

        plt.pie(cluster_dist.values,
                labels=[f'分群 {i}' for i in cluster_dist.index],
                autopct='%1.1f%%',
                colors=colors[:len(cluster_dist)])
        plt.title('客户分群分布')

        # 散点图
        plt.subplot(1, 2, 2)
        for cluster_id in sorted(self.user_features['客户分群'].unique()):
            cluster_data = self.user_features[self.user_features['客户分群'] == cluster_id]
            plt.scatter(cluster_data['购买频次'],
                        cluster_data['总消费额'],
                        label=f'分群 {cluster_id}',
                        alpha=0.6)

        plt.xlabel('购买频次')
        plt.ylabel('总消费额')
        plt.title('客户分群散点图')
        plt.legend()
        plt.tight_layout()
        plt.show()

    def get_segmented_users(self):
        """获取分群后的用户数据"""
        return self.user_features